class AreaSelector {
  constructor({ element, selectEl, selectElKey, onChangeSelected }) {
    this.element = element;
    this.selectElList = this.element.querySelectorAll(selectEl);
    this.selectElKey = selectElKey;
    this.onChangeSelected = onChangeSelected;
    
    this.selectValues = [];
    this.#createSelectArea();
    this.#handleMouseDown();
    this.#handleMouseUp();
    this.#handleContextMenu();
  }

  //   私有属性
  #area;
  #startPoint;
  #endPoint;
  #mouseMoveHandler;

  // private methods
  #createSelectArea = () => {
    this.element.style.position = "relative";
    const area = document.createElement("div");
    area.style.position = "absolute";
    area.style.border = "1px solid rgb(0,119,255)";
    area.style.background = "rgb(0,119,255,0.2)";
    this.element.appendChild(area);
    this.#area = area;
  };

  #getRelativePositionInElement = (clientX, clientY) => {
    const rect = this.element.getBoundingClientRect();
    const { left, top } = rect;
    const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = this.element;
    let x = clientX - left + scrollLeft;
    let y = clientY - top + scrollTop;
    if (x < 0) {
      x = 0;
    } else if (x > scrollWidth) {
      x = scrollWidth;
    }

    if (y < 0) {
      y = 0;
    } else if (y > scrollHeight) {
      y = scrollHeight;
    }

    return { x: Math.round(x), y: Math.round(y) };
  };

  #handleMouseDown = () => {
    this.element.addEventListener("mousedown", (e) => {
      if (e.button === 0) {
        //0 左击 2右击
        const { clientX, clientY } = e;
        this.#startPoint = this.#getRelativePositionInElement(clientX, clientY);
        // console.log("start point", this.#startPoint);
        this.#endPoint = this.#startPoint;
        // this.#updateSelectorArea();
        this.#showSelectorArea();
        this.#handleMouseMove();
      }
    });
  };

  #handleMouseMove = () => {
    this.#mouseMoveHandler = (e) => {
      const { clientX, clientY } = e;
      this.#endPoint = this.#getRelativePositionInElement(clientX, clientY);
      // console.log("end point", this.#endPoint);
      this.#updateSelectorArea();
      this.#scrollDrag(clientX, clientY);
    };
    window.addEventListener("mousemove", this.#mouseMoveHandler);
  };

  #handleMouseUp = () => {
    window.addEventListener("mouseup", () => {
      window.removeEventListener("mousemove", this.#mouseMoveHandler);
      this.#hideSelectorArea();
    });
  };

  #updateSelectorArea = () => {
    const { x: startX, y: startY } = this.#startPoint;
    const { x: endX, y: endY } = this.#endPoint;
    const left = Math.min(startX, endX);
    const top = Math.min(startY, endY);
    const width = Math.abs(startX - endX);
    const height = Math.abs(startY - endY);

    this.#area.style.left = `${left}px`;
    this.#area.style.top = `${top}px`;
    this.#area.style.width = `${width}px`;
    this.#area.style.height = `${height}px`;

    this.#getSelectItems();
  };

  #showSelectorArea = () => {
    this.#area.style.display = "block";
  };

  #hideSelectorArea = () => {
    this.#area.style.display = "none";
  };

  #getSelectItems = () => {
    // 获取所有的items
    // const items = this.element.querySelectorAll(this.selectEl);
    // 获取选择的区域
    const areaRect = this.#area.getBoundingClientRect();
    // 遍历所有的item，一次判断是否在选择区域内
    for (const item of this.selectElList) {
      // 获取item自己的rect
      const itemRect = item.getBoundingClientRect();
      // 是否有交叉
      const hasIntersection = this.#twoRectsHaveIntersection(
        areaRect,
        itemRect
      );

      item.dataset.selected = hasIntersection ? true : false;
    }

    let selectedList = this.element.querySelectorAll(
      ".item[data-selected=true]"
    );
    this.selectValues = [];
    for (const item of selectedList) {
      let value = item.dataset[this.selectElKey];
      this.selectValues.push(value);
    }
    this.onChangeSelected(this.selectValues);
  };

  #twoRectsHaveIntersection = (rect1, rect2) => {
    const left1 = rect1.left;
    const left2 = rect2.left;
    const right1 = rect1.left + rect1.width;
    const right2 = rect2.left + rect2.width;

    const top1 = rect1.top;
    const top2 = rect2.top;
    const bottom1 = rect1.top + rect1.height;
    const bottom2 = rect2.top + rect2.height;

    const width1 = rect1.width;
    const width2 = rect2.width;
    const height1 = rect1.height;
    const height2 = rect2.height;

    const noIntersection =
      left2 > right1 ||
      left1 > right2 ||
      bottom1 < top2 ||
      bottom2 < top1 ||
      width1 <= 0 ||
      width2 <= 0 ||
      height1 <= 0 ||
      height2 <= 0;

    return !noIntersection;
  };

  #scrollDrag = (mouseX, mouseY) => {
    const { x, y, width, height } = this.element.getBoundingClientRect();
    let scrollX, scrollY;
    if (mouseX < x) {
      scrollX = mouseX - x;
    } else if (mouseX > x + width) {
      scrollX = mouseX - (x + width);
    }

    if (mouseY < y) {
      scrollY = mouseY - y;
    } else if (mouseY > y + height) {
      scrollY = mouseY - (y + height);
    }

    if (scrollX || scrollY) {
      this.element.scrollBy({
        left: scrollX,
        top: scrollY,
        behavior: "auto",
      });
    }
  };

  #handleContextMenu = () => {
    this.element.addEventListener("contextmenu", (e) => {
      e.preventDefault();

      // 将弹窗的位置绑定在该位置
      const { clientX, clientY } = e;
      const point = this.#getRelativePositionInElement(clientX, clientY);
      console.log(point);
    });
  };
}
